package cn.jdemo.jsystem.classloader;

import java.io.FileInputStream;

public class CustomClzLoader2 extends ClassLoader{

	public static void main(String[] args) throws Exception {
		CustomClzLoader2 classLoader = new CustomClzLoader2("D:\\test");
		Class<?> clazz = classLoader.loadClass("cn.jdemo.jsystem.classloader.CustomClzLoader2Test");
		Class<?> clazz2 = classLoader.loadClass("cn.jdemo.jsystem.classloader.CustomClzLoader2Test");
		Object obj = clazz.newInstance();
		System.out.println(clazz.getClassLoader().getClass().getName());// cn.jdemo.jsystem.classloader.CustomClzLoader2
		System.out.println(clazz2.getClassLoader().getClass().getName());// cn.jdemo.jsystem.classloader.CustomClzLoader2
	}


	private String classPath;

	public CustomClzLoader2(String classPath) {
		this.classPath = classPath;
	}

	/**
	 * 重写findClass方法
	 *
	 * 如果不会写, 可以参考URLClassLoader中是如何加载AppClassLoader和ExtClassLoader的
	 * @see java.net.URLClassLoader#findClass
	 */
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		try {
			byte[] data = loadBytes(name);
			return defineClass(name, data, 0, data.length);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	protected Class<?> loadClass(String name, boolean resolve)
			throws ClassNotFoundException
	{
		synchronized (getClassLoadingLock(name)) {
			// First, check if the class has already been loaded
			Class<?> c = findLoadedClass(name);
			if (c == null) {
				/**
				 * 直接执行findClass()...什么意思呢? 首先会使用自定义类加载器加载类, 不在向上委托, 直接由
				 * 自己执行
				 * jvm自带的类还是需要由引导类加载器自动加载
				 */
				if (!name.startsWith("cn.jdemo.jsystem")) {
					c = this.getParent().loadClass(name);
				} else {
					// 打破双亲委托模型,直接自己加载
					c = findClass(name);
				}
			}
			if (resolve) {
				resolveClass(c);
			}
			return c;
		}
	}

	private byte[] loadBytes(String name) throws Exception {
		// 我们需要读取类的路径
		String path = name.replace('.', '/').concat(".class");
		//String path = "";
		// 去路径下查找这个类
		FileInputStream fileInputStream = new FileInputStream(classPath + "/"  + path);
		int len = fileInputStream.available();

		byte[] data = new byte[len];
		fileInputStream.read(data);
		fileInputStream.close();
		return data;
	}

}
